package utils

import (
	"bytes"
	"encoding/binary"
	"fmt"

	"golang.org/x/net/websocket"
)

type CTCPSocket struct {
	m_wBufferSize       int             //接受长度
	m_cbDataBuffer      []byte          //接受缓冲  //SOCKET_TCP_BUFFER * 8
	m_TCPSocketData     *CTCPSocketData //连接数据
	m_TCPSendSocketData *CTCPSocketData //发送数据
	m_strDesc           string          //发送描述
	m_CallLog           CallbackUserLog
	mTCPData            *tagTCPData
}

func MarkNewTCPScoket(Desc string, calllog CallbackUserLog) *CTCPSocket {
	this := &CTCPSocket{
		m_wBufferSize:       0,
		m_TCPSocketData:     MarkNewCTCPSocketData(calllog),
		m_TCPSendSocketData: MarkNewCTCPSocketData(calllog),
		m_strDesc:           Desc,
		m_CallLog:           calllog,
		mTCPData:            new(tagTCPData),
	}

	return this
}

func (this *CTCPSocket) Assemble(wMainCmdID uint16, wSubCmdID uint16, pData interface{}, pSrcData []byte) []byte {

	if pData != nil {
		buf_w := new(bytes.Buffer)
		binary.Write(buf_w, binary.LittleEndian, pData)

		if this.m_TCPSendSocketData.InitSocketData(wMainCmdID, wSubCmdID, buf_w.Bytes(), uint16(binary.Size(pData)), 0, "") == false {
			return pSrcData
		}

		return this.m_TCPSendSocketData.m_cbDataBuffer[:this.m_TCPSendSocketData.m_wBufferSize]
	}

	return nil
}

//发送函数
func (this *CTCPSocket) SendData(wMainCmdID uint16, wSubCmdID uint16, pData []byte, wDataSize uint16, Ws *websocket.Conn, cmdno uint32, key string) bool {

	if this.m_TCPSendSocketData.InitSocketData(wMainCmdID, wSubCmdID, pData, wDataSize, cmdno, key) == false {
		if this.m_CallLog != nil {
			this.m_CallLog(key, fmt.Sprintf("Desc:[%s] SendData -- InitSocketData Failed!  wMainCmdID [%d] wSubCmdID [%d] ", this.m_strDesc, wMainCmdID, wSubCmdID))
		}
		return false
	}

	if Ws == nil {
		return false
	}

	var err error
	if err = websocket.Message.Send(Ws, this.m_TCPSendSocketData.m_cbDataBuffer[:this.m_TCPSendSocketData.m_wBufferSize]); err != nil {
		if this.m_CallLog != nil {
			this.m_CallLog(key, fmt.Sprintf("Desc:[%s] Send Data To Clinet Failed!  wMainCmdID:%d wSubCmdID:%d ", this.m_strDesc, wMainCmdID, wSubCmdID))
		}
		return false
	}

	return true
}

//解包打印
func (this *CTCPSocket) DecryptData(pData []byte, CallWsClinet CallbackToWsClient, CallFoxucfun CallbackToFouxServer, key string) bool {

	this.m_wBufferSize += len(pData)
	if this.m_CallLog != nil {
		this.m_CallLog(key, fmt.Sprintf("Desc:[%s] DecryptData :%d", this.m_strDesc, this.m_wBufferSize))
	}

	//this.m_CallLog(fmt.Sprintf("Desc:[%s] 1-> this.m_cbDataBuffer = %d ", this.m_strDesc, len(this.m_cbDataBuffer)))
	this.m_cbDataBuffer = append(this.m_cbDataBuffer, pData...)
	//fmt.Println(fmt.Sprintf("len:%d cap:%d", len(this.m_cbDataBuffer), cap(this.m_cbDataBuffer)))
	//this.m_CallLog(fmt.Sprintf("Desc:[%s] 2-> this.m_cbDataBuffer = %d  m_wBufferSize = %d", this.m_strDesc, len(this.m_cbDataBuffer), this.m_wBufferSize))
	//SysLog.PutLineAsLog(fmt.Sprintf("原始数据 %v", pData))

	for {
		if this.m_wBufferSize >= int(TcpheadSize) {
			var pInfo TCP_Info
			buf := bytes.NewReader(this.m_cbDataBuffer[:])
			if err := binary.Read(buf, binary.LittleEndian, &pInfo); err != nil {
				if this.m_CallLog != nil {
					this.m_CallLog(key, fmt.Sprintf("Desc:[%s] TCP_Info Decry Failed error: %s", this.m_strDesc, err.Error()))
				}
				return false
			}

			//长度校验
			if (pInfo.WPacketSize < tcpinfoSize) || (pInfo.WPacketSize > uint16(SOCKET_TCP_BUFFER)) {
				if this.m_CallLog != nil {
					this.m_CallLog(key, fmt.Sprintf("Desc:[%s]  DataLength Size < tcpinfoSize  || DataLength size > SOCKET_TCP_BUFFER pInfo.WPacketSize=%d tcpinfoSize=%d SOCKET_TCP_BUFFER:%d", this.m_strDesc, pInfo.WPacketSize, tcpinfoSize, SOCKET_TCP_BUFFER))
				}
				return false
			}

			//完整判断
			if this.m_wBufferSize < int(pInfo.WPacketSize) {
				if this.m_CallLog != nil {
					this.m_CallLog(key, fmt.Sprintf("this.m_wBufferSize < int(pInfo.WPacketSize) [this.m_wBufferSize:%d pInfo.WPacketSize:%d]", this.m_wBufferSize, pInfo.WPacketSize))
				}
				return false
			}

			//var TCPData *tagTCPData = new(tagTCPData)
			this.mTCPData.PDataBuffer = [SOCKET_TCP_BUFFER]byte{0}
			wBufferDataSize := pInfo.WPacketSize

			if this.m_TCPSocketData.SetBufferData(this.m_cbDataBuffer, wBufferDataSize, this.mTCPData, key) == false {
				if this.m_CallLog != nil {
					this.m_CallLog(key, fmt.Sprintf("Desc:[%s] m_TCPSocketData.SetBufferData SetBufferData Failed", this.m_strDesc))
				}
				return false
			}

			if this.m_CallLog != nil {
				this.m_CallLog(key, fmt.Sprintf("Desc:[%s]  cbDataKind :%d ,cbCheckCode:%d,  package Length:%d wMianID：[%d]  SubID: [%d] Packid : [%d] ",
					this.m_strDesc,
					pInfo.CbDataKind,
					pInfo.CbCheckCode,
					pInfo.WPacketSize,
					this.mTCPData.Command.WMainCmdID,
					this.mTCPData.Command.WSubCmdID,
					pInfo.DwMessageId))
			}

			//函数回调
			if CallWsClinet != nil {
				if CallWsClinet(this.m_cbDataBuffer[:wBufferDataSize]) == false {
					if this.m_CallLog != nil {
						this.m_CallLog(key, "CallWsClinet == false")
					}
					return false
				}
			}

			//函数回调
			if CallFoxucfun != nil {
				if CallFoxucfun(this.mTCPData.Command, this.mTCPData.PDataBuffer[:this.mTCPData.WDataSize], this.m_cbDataBuffer[:wBufferDataSize], this.mTCPData.WDataSize, pInfo.DwMessageId) == false {
					if this.m_CallLog != nil {
						this.m_CallLog(key, "CallFoxucfun == false")
					}
					return false
				}
			}

			this.m_wBufferSize -= int(wBufferDataSize) //data[:0:0]
			//this.m_CallLog(key, fmt.Sprintf("key %s wBufferDataSize=%d,this.m_wBufferSize=%d ,this.m_cbDataBuffer = %d", key, wBufferDataSize, this.m_wBufferSize, len(this.m_cbDataBuffer)))
			//this.m_cbDataBuffer = append(this.m_cbDataBuffer[wBufferDataSize:], this.m_cbDataBuffer[len(this.m_cbDataBuffer):]...)
			//this.m_CallLog(fmt.Sprintf("Desc:[%s] ChangedataArrayLen: %d", this.m_strDesc, len(this.m_cbDataBuffer)))
			//this.m_CallLog(fmt.Sprintf("Desc:[%s] last BufSize = %d", this.m_strDesc, this.m_wBufferSize))

			if this.m_wBufferSize > 0 {
				SysLog.PutLineAsLog(fmt.Sprintf("key %s wBufferDataSize=%d,this.m_wBufferSize=%d ,this.m_cbDataBuffer = %d", key, wBufferDataSize, this.m_wBufferSize, len(this.m_cbDataBuffer)))
				this.m_cbDataBuffer = this.m_cbDataBuffer[wBufferDataSize:]
				if this.m_CallLog != nil {
					this.m_CallLog(key, fmt.Sprintf("Desc:[%s] ChangedataBytesLen: %d", this.m_strDesc, len(this.m_cbDataBuffer)))
				}
			} else {
				this.m_cbDataBuffer = this.m_cbDataBuffer[0:0]
			}

		} else {
			return true
		}
	}

	if this.m_CallLog != nil {
		this.m_CallLog(key, "DecryptData finish!!")
	}
	return true
}
